<template>
  <div class="employees-container">
    <div class="app-container">
      <!-- 通用工具栏组件使用 -->
      <page-tools>
        <!-- 自定义左侧内容  插槽 -->
        <template #slot-left>
          <span>共19条记录</span>
        </template>

        <!-- 自定义右侧内容 -->
        <!-- import和xeport要和权限点表示英文必须一致才能使用而且还要给员工分配上才能看到 -->
        <template #slot-right>
          <el-button
            v-power="'import'"
            type="danger"
            size="small"
            @click="uploadExcelBtnFn"
            >导入excel</el-button
          >
          <el-button
            v-power="'export'"
            type="success"
            size="small"
            @click="downloadExcel"
            >导出excel</el-button
          >
          <el-button type="primary" size="small" @click="add"
            >新增员工</el-button
          >
        </template>
      </page-tools>
      <el-card style="margin-top: 10px">
        <el-table border :data="employeesList">
          <el-table-column label="序号" type="index" />
          <el-table-column label="姓名" prop="username" />
          <el-table-column label="头像" prop="staffPhoto">
            <template v-slot="scope">
              <image-holder :src="scope.row.staffPhoto"></image-holder>
            </template>
          </el-table-column>
          <el-table-column label="手机号" prop="mobile" />
          <el-table-column
            label="工号"
            prop="workNumber"
            sortable
            :sort-method="sortMethodFn"
          />
          <!-- <el-table-column label="聘用形式" prop="formOfEmployment"> -->
          <!-- 针对聘用形式用枚举 
          第一种解决方案 采用三元表达式，但是这是两个数据的情况下 -->
          <!-- <template v-slot="scope"> -->
          <!-- scope.row.formOfEmployment ？'正式','非正式'----？左边是1或2或者字符串'1','2'都是true，原地址始终是'正式'与我们要的效果不符
              但是scope.row.formOfEmployment === 1 ? "正式" : "非正式"----?左边是一个判断===条件，争议判断结果在原地作为三元运算符判断条件
              1===1 true 2===1false(现在的效果是对的) -->
          <!-- <span> -->
          <!-- {{ scope.row.formOfEmployment === 1 ? "正式" : "非正式"}} -->
          <!-- 采用枚举的第二种方式 -->
          <!-- {{ formOfEmployment(scope.row.formOfEmployment) }} -->
          <!-- </span> -->
          <!-- </template> -->
          <!-- </el-table-column> -->
          <!-- 采用枚举的第3种方式 -->
          <el-table-column
            prop="address"
            label="聘用形式"
            :formatter="formatter"
          >
          </el-table-column>

          <el-table-column label="部门" prop="departmentName" />
          <el-table-column label="入职时间" prop="timeOfEntry">
            <template v-slot="scope">
              {{ formatTime(scope.row.timeOfEntry) }}
            </template>
          </el-table-column>
          <el-table-column label="操作" width="280">
            <template v-slot="scope">
              <el-button
                type="text"
                size="small"
                @click="$router.push(`/Employees/detail?id=${scope.row.id}`)"
                >查看</el-button
              >
              <el-button
                type="text"
                size="small"
                @click="distribution(scope.row.id)"
                >分配角色</el-button
              >
              <el-button type="text" size="small" @click="delFn(scope.row.id)"
                >删除</el-button
              >
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页组件 -->
        <el-row
          type="flex"
          justify="center"
          align="middle"
          style="height: 60px"
        >
          <!-- 分页区域 -->
          <el-pagination
            :current-page="query.page"
            :page-sizes="[10, 15, 20, 25]"
            :page-size="query.size"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          />
        </el-row>
      </el-card>
      <!-- 新增员工弹框+表单组件 
      close这个是element内置的组件	Dialog 关闭的回调-->
      <el-dialog title="新增员工" :visible.sync="showDialog" @close="close">
        <emp-dialog
          ref="empForm"
          :show-dialog.sync="showDialog"
          :depart-list="departList"
          @addEmpFn="addEmployeeFn"
        />
      </el-dialog>
      <!-- 分配角色 -->
      <el-dialog :visible.sync="imageHolder">
        <assign-role-dialog
          @close="closeFn"
          :role-list="roleList"
          :role-ids="roleIds"
          @transmit="transmit"
        />
      </el-dialog>
    </div>
  </div>
</template>

<script>
import { getEmployeeListAPI, departmentAPI, addEmployee, delEmployeeAPI, getRolesAPI, getUserDetailByIdAPI, assignRolesAPI } from '@/api'
import Employees from '@/api/constant/employees'
import EmpDialog from './components/empDialog.vue'
import dayjs from 'dayjs'
// 树形结构的转换方法
import { transTree } from '@/utils'
import AssignRoleDialog from './components/assignRoleDialog.vue'


export default {
  name: 'Employees',
  data () {
    return {
      query: {
        page: 1, // 页码
        size: 10 // 每页条数
      },
      employeesList: [], // 员工列表
      total: 0,// 数据总条数
      showDialog: false,//弹框显示
      departList: [],//树形部门数据
      imageHolder: false,//角色显示弹框
      roleList: [], // 角色列表数据
      roleIds: [], // 被选中项那个
      roleId: '',//获取id,查看分配

    }
  },
  created () {
    // 获取员工列表
    // 注意：生命周期方法，没有挂载到this组件对象身上,this.created（）是错误的
    this.getEmployeeList()
    // 获取部门数据
    this.departmentsList()
    // 角色列表数据
    this.getRolesList()
  },
  components: {
    EmpDialog,
    AssignRoleDialog
  },
  methods: {
    // 角色列表数据
    async getRolesList () {
      const res = await getRolesAPI({
        // 默认是获取了第一页10条，但是后台应该默认返回所有（然后指定页面和页码才应该返回段数，所以但是我们只能先传1000解决这个问题）
        page: 1,
        pagesize: 1000

      })
      console.log(res)
      this.roleList = res.data.rows//数据给角色
    },
    // 格式化入职日期的方法
    formatTime (time) {
      return dayjs(time).format('YYYY-MM-DD')
    },
    // 获取员工列表
    async getEmployeeList () {
      const res = await getEmployeeListAPI(this.query)//接口让传的
      // console.log(res)
      // 如何把所有的数据都参与到排序？
      // 思路1：让后台写，你需要给后台发送拍讯的字段（升序还是降序,要哪一页多少条），后台有所有的数据，把所有数据进行排序，你要第几页多少条,返回第几段往后的条数的数据
      // 思路2：前端写，你需要pageSize改很大，把所有数据请求回来（前提）
      // 分页分段，排序，都自己在次函数中拿到数据后，自己拍讯，根据页码和条数，自己分段取值返回ei-Table
      // 数组截取的方法slice()
      // console.log(res)
      if (res.data.rows.length === 0 && this.query.page > 1) {
        // 问题：当前页面删除最后一条，页码回去了，但是数据不回去
        // 解决
        // 证明当前页码的数据后台没有了，页码--，再次发起请求
        // 回到前一页重新请求书记，如果老板要求直接回到第一页，=1
        // 如果当前为第一页没有数据那就是没有了，所以 page > 1的时候才能减减
        this.query.page--

        this.getEmployeeList()
      }
      this.employeesList = res.data.rows//员工列表
      this.total = res.data.total//数据总条数
    },
    // 获取弹框部门列表
    async departmentsList () {
      const res = await departmentAPI()
      // console.log(res)
      // 在里面进行转换树形结构
      this.departList = transTree(res.data.depts, '')

    },
    // 每页显示的条数发生改变时触发
    handleSizeChange (newSize) {
      console.log(newSize)
      this.query.size = newSize
      this.getEmployeeList()//刷新列表
    },

    // 当前页面发生改变时触发
    handleCurrentChange (newPage) {
      console.log(newPage)
      this.query.page = newPage
      this.getEmployeeList()//刷新列表
    },
    // 格式化聘用形式的数字转换文字
    // 采用枚举的第二种方式
    // formOfEmployment (num) {
    //   const obj = {
    //     1: '正式',
    //     2: '非正式'
    //     // 若是将来有3,4,5就按照这种对应的格式来写
    //   }
    //   // 知识点39：对象.具体的key名（key必须已经在对应里了)
    //   // 对象[变量]
    //   return obj[num]
    // },
    // 格式化聘用形式的数字转换文字
    // 采用枚举的第三种方式
    formatter (row) {
      const obj = Employees.hireType.find(item => item.id === row.formOfEmployment)
      return obj ? obj.value : '非正式'
    },
    // 工号列的排序
    sortMethodFn (a, b) {
      // a和b是数组里相邻的2个值（数据对象）
      // 这里和数据的sort方法使用一致
      return a.workNumber - b.workNumber//字符串相减，会自动转换成数字，返回数字
    },
    // 新增员工弹框
    add () {
      this.showDialog = true
    },
    // 确定按钮
    async addEmployeeFn (objData) {
      console.log(objData)
      const res = await addEmployee(objData)
      console.log(res)
      this.getEmployeeList()//刷新列表
    },
    // 关闭
    close () {
      // 关闭弹窗是组件内传值给:visible,sync方式右侧的变量然后流回到组件内，隐藏标签
      this.$refs.empForm.$refs.addForm.resetFields()//重置表单
    },
    // 删除
    async delFn (id) {
      console.log(id)
      const result = await this.$confirm('确定是否删除吗, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      console.log(result)
      if (confirm) {
        await delEmployeeAPI(id)//参数需要id
      }

      this.getEmployeeList()//刷新
    },
    // 导入表格-按钮->点击事件
    uploadExcelBtnFn () {
      // 跳转二级路由到专门上传表格的页面
      this.$router.push('/excel')
    },
    // 导出excel
    downloadExcel () {
      // import('@/vendor/Export2Excel') 相当于 import {excel} from '@/vendor/Export2Excel'
      // 目标：模块内是export按需打出的，现在导入如何变成一个大对象
      // import * as 变量名 from '模块'
      // 变量名是一个对象，key就是按需导出的变量名

      // 为何他用函数
      // 此外，还有一个类似函数的动态import（）,它不需要type='module'的script标签
      // 这里用方法导入的是一个对象里有按需导出的方法

      // 数据转换开始
      //  重要：页面el- table数据怎么铺设，和导出的表格之间没有决定性关系 是聘用形式
      // 导出表格的数据，是我们自己用js代码定义的
      // 1.header要的页面上显示是一样的，都要中文的列标题
      // 操作例不是数据就不要了
      const headerArr = ['姓名', '序号', '头像', '头像', '手机号', '聘用形式', '部门', '入职时间'] // 表头 必填
      // 2.对象里所有值-转成数组
      // Object.keys()把传入的对象上多有的key收集成一个数组['id','mobile']
      // Object.value()把传入的对象上所有value收集成一个数组['001', '131313132121']
      // 上面两个方法弊端：对象是无序的，因此获取的值也是无序的
      //    map会手机return的值，在行成外层的大数组
      // 循环完毕应该这样的[['0001', '123456'], ['0002', '45679']....]

      // 1.定义对照对象，中文：英文key
      const keyObj = {
        '序号': 'id',
        '姓名': 'username',
        '头像': 'staffPhoto',
        '手机号': 'mobile',
        '工号': 'workNumber',
        '聘用形式': 'formOfEmployment',
        '部门': 'departmentName',
        '入职时间': 'timeOfEntry'
      }
      // 2.遍历headerArr数组，拿出中文，换出英文key
      const valueArr = this.employeesList.map((obj, index) => {//遍历每个数据对象，用中文key，去数据对象里找到值，形成数组
        // 3.再到数据对象里取出对应的值，数组遍历是有顺序的
        // 4.拿到值放入一个数组里
        // 5.2层循环
        const newArr = []
        headerArr.forEach(item => {
          const enValue = keyObj[item]//获取中文的key
          // console.log(enValue)//id,staffPhoto,username,mobile,workNumber,formOfEmployment,departmentName,timeOfEntry
          if (enValue === 'id') {
            newArr.push(index + 1)
          } else if (enValue === 'formOfEmployment') {//判断聘用形式
            const data = Employees.hireType.find(item => Number(item.id) === Number(obj[enValue]))
            newArr.push(data ? data.value : '非正式')
          } else {
            const value = obj[enValue]//取值
            newArr.push(value)
          }
        })
        return newArr
      })


      // const valueArr = this.employeesList.map(item => {
      //   return Object.values(item)
      // })
      // console.log(valueArr)
      import('@/vendor/Export2Excel').then(excel => {
        // excel表示导入的模块对象
        excel.export_json_to_excel({
          header: headerArr,//表头 必填
          data: valueArr, // 具体数据 必填
          // 问题:点击浏览器卡死，因为数据格式不对
          filename: '人资管理', // 文件名称
          autoWidth: true, // 宽度是否自适应
          bookType: 'xlsx' // 生成的文件类型
        })
      })
    },
    // 分配角色弹框
    distribution (id) {
      this.imageHolder = true//弹框显示
      this.roleId = id
      // console.log(id)
      this.getUserDetailByIdList()//获取点击这个人的已有角色列表



    },
    // 分配角色显示弹框的取消和确定
    closeFn () {
      this.imageHolder = false//弹框不显示
    },
    // 获取点击这个人的已有角色列表
    async getUserDetailByIdList () {
      const res = await getUserDetailByIdAPI(this.roleId)
      console.log(res)
      this.roleIds = res.data.roleIds//回显===我写的 目前没有报错
      // if(!res.success)return this.$message.error(res.success)
      // this.roleId=res.data.roleIds||[]//如果后台发现rolesIds没有就返回null，导致assignRoleDialog的watch里...null报空，所以要是没有值给个空数组，...[]是不会报错的

    },
    // 分配角色确定按钮
    async transmit (roleIds) {//传过来的时候就是对象里面当前点击选的那个
      // console.log(roleId)//{success: true, code: 10000, data: {…}, message: '获取用户基本信息成功'}
      const res = await assignRolesAPI({
        id: this.roleId,
        roleIds: roleIds
      })
      console.log(res)
    }
  }
}
</script>

<style lang="scss" scoped></style>